package org.com.andy.controller;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.util.StrUtil;
import com.google.protobuf.ServiceException;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.com.andy.domain.R;
import org.com.andy.domain.dto.FlowBizKeyDto;
import org.com.andy.domain.dto.FlowProcDefDto;
import org.com.andy.domain.dto.FlowStartDto;
import org.com.andy.domain.dto.FlowTaskDto;
import org.com.andy.domain.dto.FlowUpdateStsteDto;
import org.com.andy.service.IFlowDefinitionService;
import org.com.andy.web.domain.AjaxResult;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.zip.ZipInputStream;

@Slf4j
@RestController
@RequestMapping("/flowable")
public class FlowDefinitionController {

    @Resource
    private IFlowDefinitionService flowDefinitionService;

//    @Resource
//    ObsServiceProvider obsServiceProvider;


//    @GetMapping(value = "/flowable/definition/list")
//    @ApiOperation(value = "流程定义列表", response = FlowProcDefDto.class)
//    public AjaxResult list(FlowQueryVo queryVo) {
//        return AjaxResult.success(flowDefinitionService.list(queryVo));
//    }

    @GetMapping(value = "/flowable/definition/manualDeployment")
    @ApiOperation(value = "手动部署processes目录文件", response = FlowProcDefDto.class)
    public AjaxResult manualDeployment() {
        return AjaxResult.success(flowDefinitionService.manualDeployment());
    }


    @ApiOperation(value = "importByObs", notes = "importByObs")
    @PostMapping("/flowable/definition/importByObs")
    public AjaxResult importByObs() {
        flowDefinitionService.importByObs();

        return AjaxResult.success("导入成功");
    }


    @ApiOperation(value = "导入流程文件", notes = "上传bpmn20的xml文件")
    @PostMapping("/flowable/definition/import")
    public AjaxResult importFile(@RequestParam(required = false, defaultValue = "manual_import_xml") String name,
                                 @RequestParam(required = false, defaultValue = "noSetCategory") String category,
                                 @RequestParam("file") MultipartFile file) {
        InputStream in = null;
        try {
            in = file.getInputStream();
            if (StrUtil.isEmpty(name)) {
                name = file.getOriginalFilename();
            }
            ProcessDefinition processDefinition = flowDefinitionService.importFile(name, category, in);

            String[] strings = name.split("\\.");
            String dirName = strings[0];
            String datetime = DateTime.now().toString();
            StringBuilder stringBuilder = new StringBuilder();

//            stringBuilder.append(ServiceNameConstants.WORKFLOW_SERVICE).append("/")
            stringBuilder.append("WORKFLOW_SERVICE").append("/")
                    .append(dirName).append("/")
                    .append(datetime).append("/")
                    .append(dirName).append("(").append(processDefinition.getVersion()).append(")").append(".bpmn20.xml");


//            obsServiceProvider.saveFile(file, stringBuilder.toString());
        } catch (Exception e) {
            log.error("导入失败:", e);
            return AjaxResult.success(e.getMessage());
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                log.error("关闭输入流出错", e);
            }
        }

        return AjaxResult.success("导入成功");
    }


    @ApiOperation(value = "导入流程文件zip", notes = "上传bpmn20的zip文件")
    @PostMapping("/definition/importZipFiles")
    public AjaxResult importZipFiles(@RequestParam(required = false, defaultValue = "manual_import_zip") String name,
                                     @RequestParam(required = false, defaultValue = "noSetCategory") String category,
                                     @RequestParam("files") MultipartFile files) {
        ZipInputStream zipInputStream = null;
        try {

            String type = FileTypeUtil.getType(files.getInputStream(), files.getOriginalFilename());

            if (!type.equalsIgnoreCase("zip")) {
                throw new ServiceException("文件类型不是zip格式");
            }

            zipInputStream = new ZipInputStream(files.getInputStream(), StandardCharsets.UTF_8);
            List<ProcessDefinition> processDefinition = flowDefinitionService.importZipFiles(name, category, zipInputStream);

        } catch (Exception e) {
            log.error("导入失败:", e);
            return AjaxResult.error(e.getMessage());
        } finally {
            try {
                if (zipInputStream != null) {
                    zipInputStream.close();
                }
            } catch (IOException e) {
                log.error("关闭输入流出错", e);
            }
        }

        return AjaxResult.success("导入成功");
    }

    @ApiOperation(value = "设置流程定义类别")
    @PostMapping("/definition/updateCategory")
    public AjaxResult updateCategory(@RequestParam(value = "procDefId") String procDefId, @RequestParam("category") String category) {
        flowDefinitionService.updateCategory(procDefId, category);
        return AjaxResult.success();
    }


    @ApiOperation(value = "读取xml文件")
    @GetMapping("/flowable/definition/readXml/{deployId}")
    public AjaxResult readXml(@ApiParam(value = "流程定义id") @PathVariable(value = "deployId") String deployId) {
        try {
            return flowDefinitionService.readXml(deployId);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("加载xml文件异常");
        }

    }

    @ApiOperation(value = "读取图片文件")
    @GetMapping("/flowable/definition/readImage/{deployId}")
    public void readImage(@ApiParam(value = "流程定义id") @PathVariable(value = "deployId") String deployId, HttpServletResponse response) {
        OutputStream os = null;
        BufferedImage image = null;
        try {
            image = ImageIO.read(flowDefinitionService.readImage(deployId));
            response.setContentType("image/png");
            os = response.getOutputStream();
            if (image != null) {
                ImageIO.write(image, "png", os);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//
//    @ApiOperation(value = "发起流程")
//    @PostMapping("/flowable/definition/start")
//    public R<FlowTaskDto> start(@RequestBody FlowStartDto flowStartDto) {
//        return flowDefinitionService.startProcessInstanceById(flowStartDto);
//    }

    @ApiOperation(value = "根据Key发起流程")
    @PostMapping("/flowable/definition/startByKey")
    public R<FlowTaskDto> startByKey(@RequestBody FlowStartDto flowStartDto) {
        return flowDefinitionService.startProcessInstanceByKey(flowStartDto.getProcDefKey(), flowStartDto.getBusinessKey(), flowStartDto.getVariables());
    }

    @ApiOperation(value = "根据Key终止流程")
    @PostMapping("/flowable/definition/stopByKey/{businessKey}")
    public R<Boolean> stopByKey(@PathVariable(value = "businessKey") String businessKey) {
        return flowDefinitionService.stopProcessInstanceByKey(businessKey);
    }

    @ApiOperation(value = "根据Key发起流程")
    @PostMapping("/flowable/definition/startByKeyWithBusinessKey")
    public AjaxResult startByKeyWithBusinessKey(@RequestBody FlowStartDto flowStartDto) {
        return flowDefinitionService.startProcessByKeyWithBusinessKey(flowStartDto);
    }

    @ApiOperation(value = "发起流程根据Bizkey")
    @PostMapping("/flowable/definition/startByBusinessKey")
    public R<FlowBizKeyDto> startByBusinessKey(@RequestBody FlowBizKeyDto flowBizKeyDto) {
        return flowDefinitionService.startByBusinessKey(flowBizKeyDto.getProcessDefinitionId(), flowBizKeyDto.getBusinessKey(), flowBizKeyDto.getTransientVariables(), flowBizKeyDto.getVariables());
    }

    @ApiOperation(value = "激活流程定义")
    @PostMapping("/flowable/definition/activationProcess")
    public AjaxResult activationProcess(@RequestBody FlowUpdateStsteDto flowUpdateStsteDto) {
        flowDefinitionService.activationProcess(flowUpdateStsteDto.getDeployId());
        return AjaxResult.success();
    }

    @ApiOperation(value = "挂起流程定义")
    @PostMapping("/flowable/definition/suspendProcess")
    public AjaxResult suspendProcess(@RequestBody FlowUpdateStsteDto flowUpdateStsteDto) {
        flowDefinitionService.suspendProcess(flowUpdateStsteDto.getDeployId());
        return AjaxResult.success();
    }

    @ApiOperation(value = "删除流程")
    public AjaxResult delete(@PathVariable String[] deployIds) {
        for (String deployId : deployIds) {
            flowDefinitionService.delete(deployId);
        }
        return AjaxResult.success();
    }

    @ApiOperation(value = "预警工单发起流程")
    @PostMapping("/flowable/definition/earlyWarningTicketsStart")
    public R<FlowTaskDto> earlyWarningTicketsStart(@RequestBody FlowStartDto flowStartDto) {
        return flowDefinitionService.earlyWarningTicketsStart(flowStartDto.getProcDefId(), flowStartDto.getVariables());
    }

}
